#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include "LockGuard.hpp"

using std::vector;

const int default_size = 5;

template <typename T>
class RingQueue
{
    vector<T> ringqueue;
    int _size;

    int pro_step; // 生产者指针
    int con_step; // 消费者指针

    sem_t _space_sem; // 生产
    sem_t _data_sem;  // 消费

    pthread_mutex_t pro_mutex;
    pthread_mutex_t con_mutex;

    void P(sem_t &sem)
    {
        // 将信号量的值-1
        sem_wait(&sem); // 原子的
    }
    void V(sem_t &sem)
    {
        // 将信号量的值+1
        sem_post(&sem); // 原子的
    }

public:
    RingQueue(int size = default_size) : ringqueue(size), _size(size)
    {
        sem_init(&_space_sem, 0, size);
        sem_init(&_data_sem, 0, 0);

        pthread_mutex_init(&pro_mutex, nullptr);
        pthread_mutex_init(&con_mutex, nullptr);
    }
    ~RingQueue()
    {
        sem_destroy(&_space_sem);
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&pro_mutex);
        pthread_mutex_destroy(&con_mutex);
    }

    void Push(const T &in)
    {

        // 先申请信号量 , 得到一部分资源,再申请锁，线程单一通过
        P(_space_sem);  

        {
            LockGuard lockguard(&pro_mutex);

            ringqueue[pro_step++] = in;
            pro_step %= _size;
        }

        V(_data_sem);
    }

    void Pop(T *out)
    {

        P(_data_sem);

        {
            LockGuard lockguard(&con_mutex);

            *out = ringqueue[con_step++];
            con_step %= _size;
        }

        V(_space_sem); // 空间资源增加
    }
};